#include "keyword.hxx"
#include <cassert>
#include <sstream>
#include <utility.hxx>
#include <boost/regex.hpp>
#include <locale>

using namespace std;

Keyword::Keyword(const string& desc)
:m_Desc(desc)
{
	Parse();
}
bool Keyword::Is3Tong(const string& result)
{
	std::map<char, int> charOccurMap;

	int maxOccur = 0;
	for (size_t i=0; i<result.length(); i++)
	{
		if (isalnum(result[i]))
		{
			charOccurMap[result[i]] = charOccurMap[result[i]] + 1;

			if (maxOccur < charOccurMap[result[i]])
				maxOccur = charOccurMap[result[i]];
		}
	}

	return (maxOccur >= 3);
}

bool Keyword::IsValuable(const string& result)
{
	if (Is3Tong(result))
		return true;
	
	if (string::npos != result.find("4"))
		return false;

	if (string::npos != result.find("SB"))
		return false;

	if (string::npos != result.find("88"))
		return true;

	return false;
}

bool Keyword::IsMatched(const string& result) const
{
    boost::regex pat(Desc);
	boost::smatch matches;

	return boost::regex_search(result, matches, pat, boost::regex_constants::match_perl|boost::regex_constants::match_stop|boost::regex_constants::match_stop|boost::regex_constants::match_any);
}
// Find into Name if 3 same alnums.
bool Keyword::Is3TongTargeted(void) const
{
	return Is3Tong(Desc);
}
const string& Keyword::GetSpec(void) const
{
	return spec;
}
const std::set<std::string> Keyword::GetExtSpecs(void) const
{
	// move the valid joined chars to create.
	std::set<std::string> results;

	//std::string specStr = spec;
	//Utility::Replace(specStr, ' ');

	//int spaceNum = KeywordLength-specStr.length();
	//for (int i=0;i<=spaceNum; i++)
	//{
	//	string extSpec = Utility::SpaceStr(i) + specStr + Utility::SpaceStr(spaceNum - i);
	//	assert(extSpec.length() == KeywordLength);
	//	
	//	results.insert(extSpec);
	//}

	return results;
}
/**
 * 1. get fixed beginning or ending.
 **/
bool Keyword::Parse()
{
	if (Desc.empty())
		return false;

	boost::regex pat("^\\*+");
	boost::smatch matches;

	Desc = boost::regex_replace(Desc, pat, "", boost::regex_constants::match_perl|boost::regex_constants::match_stop|boost::regex_constants::match_stop|boost::regex_constants::match_any);

	/* any start or end fixed, like ^ and $. */
	int i;
	int alNumLen = 0;
	int maxOccur = 0;
	std::map<char, int> charOccurMap;

	if (Desc[0] == '^')
	{
		for (i = 1; i<Desc.length(); i++)
		{
			if (isalnum(Desc[i]))
			{
				charOccurMap[Desc[i]] = charOccurMap[Desc[i]] + 1;
				if (maxOccur < charOccurMap[Desc[i]])
					maxOccur = charOccurMap[Desc[i]];
				++alNumLen;
			}
			else if (Desc[i] == '.')
				continue;
			else
				break;
		}

		if (alNumLen>1)
		{
			spec = Desc.substr(1, i-1);
			spec = spec + Utility::SpaceStr(Keyword::KeywordLength - spec.length());
		}
	}
	else if (Desc[Desc.length()-1] == '$')
	{
		for (i = Desc.length() - 2; i >= 0; i--)
		{
			if (isalnum(Desc[i]))
			{
				charOccurMap[Desc[i]] = charOccurMap[Desc[i]] + 1;
				if (maxOccur < charOccurMap[Desc[i]])
					maxOccur = charOccurMap[Desc[i]];
				++alNumLen;
			}
			else if (Desc[i] == '.')
				continue;
			else
				break;
		}

		if (alNumLen>1)
		{
			spec = Desc.substr(i+1, Desc.length() - 1 - (i + 1));
			spec = Utility::SpaceStr(Keyword::KeywordLength - spec.length()) + spec;
		}
	}

	// remove any that is not of most occurance.
	for (std::map<char, int>::iterator iter = charOccurMap.begin(); iter != charOccurMap.end(); ++iter)
	{
		if (iter->second != maxOccur)
		{
			Utility::Replace(spec, iter->first, ' ');
		}
	}

	Utility::Replace(spec, '.', ' ');
	
	return spec.length() == Keyword::KeywordLength && alNumLen >= 2;
}